using System;
using System.Threading;
using System.Collections.Generic;
using log4net;

namespace Storage
{
    using EntityModels;

    #region PrivacyLevel

    /// <summary>
    /// The privacy levels of TripLoa's informations.
    /// </summary>
    public enum PrivacyLevel : byte
    {
        /// <summary>
        /// Not Visible Level.
        /// </summary>
        NotVisible = 0,
        /// <summary>
        /// Low Level.
        /// </summary>
        Low = 1,
        /// <summary>
        /// Medium Level.
        /// </summary>
        Medium = 2,
        /// <summary>
        /// High Level.
        /// </summary>
        High = 3
    }

    #endregion

    #region FunctionalExtensions
    
    /// <summary>
    /// Contains extension methods that help program in a functional way.
    /// </summary>
    static class FunctionalExtensions
    {
        public static void ForEach<T>(this IEnumerable<T> coll, Action<T> action)
        {
            foreach (T item in coll)
                action(item);
        }
    } 

    #endregion

    #region StorageManager
   
    /// <summary>
    /// Rapresents the way in which the modules can handle and persist their own data.
    /// </summary>
    public sealed partial class StorageManager
    {
        #region Singleton

        /// <summary>
        /// The unique instance of this class.
        /// </summary>
        private static readonly StorageManager _instance = new StorageManager();

        /// <summary>
        /// Gets the single instance of this class.
        /// </summary>
        public static StorageManager Instance
        {
            get { return _instance; }
        }

        /// <summary>
        /// Private constructor. 
        /// <remarks>This class can not be instantiated.</remarks>
        /// </summary>
        private StorageManager()
        {
#if LOG
            _logger.Info("Created StorageManager");
#endif
        }

        #endregion

        #region Private fields: _dataContextSlot, _logger

        private LocalDataStoreSlot _dataContextSlot = Thread.GetNamedDataSlot("DataContext");   
#if LOG
        private readonly ILog _logger = LogManager.GetLogger(typeof(StorageManager));
#endif
        #endregion

        #region Public properties: Entities

        /// <summary>
        /// Gets the TripLoaDataContext, used as a root for all Linq To SQL queries.
        /// </summary>
        public TripLoaDataContext Entities
        {
            get
            {
                TripLoaDataContext dc = (TripLoaDataContext)Thread.GetData(_dataContextSlot);

                if (dc == null)
                    dc = createDataContext();

                return dc;
            }
        }

        #endregion

        #region Public methods: DisposeDataContext

        /// <summary>
        /// Disposes the data context currently associated with the current thread   
        /// and removes it from the thread context. If no data context is asssociated   
        /// with the current thread, does nothing.   
        /// </summary>   
        public void DisposeDataContext()
        {
            TripLoaDataContext dc = (TripLoaDataContext)Thread.GetData(_dataContextSlot);

            if (dc != null)
            {
                dc.Dispose();
                Thread.SetData(_dataContextSlot, null);
#if LOG
                _logger.Info("DisposeDataContext");
#endif
            }
        }

        #endregion

        #region Private methods: createDataContext

        /// <summary>
        /// Creates new data context and stores it in the current thread's context.   
        /// If data context already exists, do nothing.   
        /// </summary>
        private TripLoaDataContext createDataContext()
        {
            TripLoaDataContext dc;
#if TEST
            dc = new TripLoaDataContext(
                Properties.Settings.Default.LocalTripLoaDbConnectionString);
#elif LOCAL
            dc = new TripLoaDataContext(
                Properties.Settings.Default.TripLoaDbConnectionString);
#else
            dc = new TripLoaDataContext(
                Properties.Settings.Default.RemoteTripLoaDbConnectionString);
#endif
            Thread.SetData(_dataContextSlot, dc);
#if LOG
            _logger.Info("createDataContext");
#endif
            return dc;
        }

        #endregion
    }
 
    #endregion
}
